package org.cerberus.platform.internal.impl;

import java.lang.reflect.Method;

import org.cerberus.platform.api.LoadStrategy;
import org.cerberus.platform.internal.domain.IComponentClass;
import org.cerberus.platform.internal.domain.IComponentClassAttribute;

/**
 * @author Christian Humer
 */
final class ComponentClassAttribute implements IComponentClassAttribute {

	private String name;
	private IComponentClass clazz;
	private Class<?> javaType;
	private Method setter;
	private Method getter;
	private int declaredIndex;
	private int index;
	
	ComponentClassAttribute(String name, 
			IComponentClass clazz,
			Class<?> javaType,
			Method getter,
			Method setter) {
		this.name = name;
		this.javaType = javaType;
		this.clazz = clazz;
		this.setter = setter;
		this.getter = getter;
	}

	void defineIndex(int declared, int index) {
		this.declaredIndex = declared;
		this.index = index;
	}
	
	/* For unit tests*/
	Class<?> getJavaType() {
		return javaType;
	}
	
	/* For unit tests */
	Method getSetter() {
		return setter;
	}
	
	/* For unit tests */
	Method getGetter() {
		return getter;
	}
	
	public boolean isReadOnly() {
		return setter == null || !clazz.isPrimitive();
	}
	
	public String getName() {
		return name;
	}
	
	public int getIndex() {
		return index;
	}

	@Override
	public int getDeclaredIndex() {
		return declaredIndex;
	}

	@Override
	public IComponentClass getAttributeClass() {
		return clazz;
	}
	@Override
	public LoadStrategy getFetchType() {
		return null;
	}
	
	
	@Override
	public String toString() {
		StringBuilder b = new StringBuilder();
		b.append("[");
		b.append(index);
		b.append("]");
		b.append(clazz.getClassID());
		b.append(" ");
		b.append(name);
		if (isReadOnly()) {
			b.append(" [readonly]");
		}
		return b.toString();
	}

	@Override
	public Object get(Object source) throws Throwable {
		return getter.invoke(source);
	}

	@Override
	public void set(Object source, Object value) throws Throwable {
		if (!isReadOnly()) {
			if (value == null && javaType.isPrimitive()) {
				setter.invoke(source, SystemClasses.getPrimitiveDefaultValue(javaType));
			} else {
				setter.invoke(source, value);
			}
		} else {
			throw new ComponentClassException("Attribute "+toString()+" is readonly.");
		}
	}
	
}
